package org.muninn.niagara.math;

import javax.baja.status.BStatusBoolean;
import javax.baja.status.BStatusNumeric;
import javax.baja.sys.BComponent;
import javax.baja.sys.BDynamicEnum;
import javax.baja.sys.BEnumRange;
import javax.baja.sys.BIcon;
import javax.baja.sys.Context;
import javax.baja.sys.Flags;
import javax.baja.sys.Property;
import javax.baja.sys.Sys;
import javax.baja.sys.Type;

public class BRangeTest extends BComponent
{
  public static final int[] ordinals = {0, 1};
  public static final String[] tags = {"Within", "Outside"};
  
  /** Value to cbe compared to the range **/
  public static final Property in = newProperty(Flags.SUMMARY, new BStatusNumeric());
  public void setIn(BStatusNumeric v) { set(in, v); }
  public BStatusNumeric getIn() { return (BStatusNumeric) get(in); }
  
  /** Enum to set whether <code>in</code> must fall inside or outside the range **/
  public static final Property mode = newProperty(0, BDynamicEnum.make(0, BEnumRange.make(ordinals, tags)));
  public void setMode(BDynamicEnum v) { set(mode, v); }
  public BDynamicEnum getMode() { return (BDynamicEnum) get(mode); }
  
  /** Determines whether or not limits are included in the range **/
  public static final Property inclusive = newProperty(0, true);
  public void setInclusive(boolean b) { setBoolean(inclusive, b); }
  public boolean getInclusive() { return getBoolean(inclusive); }
  
  /** Upper bound for the range **/
  public static final Property upperBound = newProperty(Flags.SUMMARY, new BStatusNumeric());
  public void setUpperBound(BStatusNumeric v) { set(upperBound, v); }
  public BStatusNumeric getUpperBound() { return (BStatusNumeric) get(upperBound); }
  
  /** Lower bound for the range **/
  public static final Property lowerBound = newProperty(Flags.SUMMARY, new BStatusNumeric());
  public void setLowerBound(BStatusNumeric v) { set(lowerBound, v); }
  public BStatusNumeric getLowerBound() { return (BStatusNumeric) get(lowerBound); }
  
  /** Indicates whether or not <code>in</code> satisfies the range requirements **/
  public static final Property out = newProperty(Flags.SUMMARY|Flags.READONLY, new BStatusBoolean());
  public void setOut(BStatusBoolean v) { set(out, v); }
  public BStatusBoolean getOut() { return (BStatusBoolean) get(out); }
  
  public void started() { doExecute(); }
  
  public void changed(Property p, Context cx)
  {
    if (!isRunning())
      return;
    
    if (!p.equals(out))
      doExecute();
  }
  
  public void doExecute()
  {
    double upper = getUpperBound().getValue();
    double lower = getLowerBound().getValue();
    boolean inclusive = getInclusive();
    int ineq = getMode().getOrdinal();
    double input = getIn().getValue();
    
    if (inclusive)
    {
      if (ineq == 0)
        getOut().setValue(input <= upper && input >= lower);
      
      else
        getOut().setValue(input >= upper || input <= lower);
    }
    
    else
    {
      if (ineq == 0)
        getOut().setValue(input < upper && input > lower);
      
      else
        getOut().setValue(input > upper || input < lower);
    }
  }
  
  public BIcon getIcon() { return icon; }
  private static final BIcon icon = BIcon.make("local:|module://muninn/org/muninn/niagara/graphics/MuninnGroup.PNG");

  public static final Type TYPE = Sys.loadType(BRangeTest.class);
  public Type getType() { return TYPE; }
}
